package com.sinosoft.hydra.um.services;

import cn.com.sinux.spring.exception.BusinessException;
import cn.com.sinux.spring.utils.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sinosoft.hydra.um.condition.SearchEBomCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.model.EBOMWordInfo;
import com.sinosoft.hydra.um.domain.model.EBomMake;
import com.sinosoft.hydra.um.domain.model.LabDataParser;
import com.sinosoft.hydra.um.domain.permission.*;
import com.sinosoft.hydra.um.helper.AuthContextHelper;
import com.sinosoft.hydra.um.repositories.TEBomDAO;
import com.sinosoft.hydra.um.repositories.TEBomRelationDAO;
import com.sinosoft.hydra.um.services.component.dataoutput.DataWriter;
import com.sinosoft.hydra.um.services.component.dataoutput.ExcelDataWriter;
import com.sinosoft.hydra.um.services.component.dataoutput.RowTemplate;
import com.sinosoft.hydra.um.services.component.dataoutput.parsers.ColumnParser;
import freemarker.template.Configuration;
import freemarker.template.Template;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.WritableCell;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.tools.zip.ZipOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.*;
import javax.transaction.Transactional;
import java.io.*;
import java.util.*;

/**
 * Created by Administrator on 2016/7/5.
 */
@Service
@Transactional
public class SysEBomService {

    @Autowired
    private SysPBomService sysPBomService;
    @Autowired
    private TEBomDAO teBomDAO;
    @Autowired
    private TEBomRelationDAO teBomRelationDAO;
    @Autowired
    private SysRecordMatchService sysRecordMatchService;
    @Autowired
    private FileService fileService;

    public List<TEBom> reset(TEBom root) {
        List<TEBom> teBoms = new ArrayList<TEBom>();
        teBoms.add(root);
        List<TEBom> children = root.getChildren();
        if (ValidatorUtils.isArrayEmpty(children)) {
            return teBoms;
        }
        for (TEBom teBom : children) {
            if (root.getNodeLevel() == null) {
                root.setNodeLevel(1);
            }
            teBom.setNodeLevel(root.getNodeLevel() + 1);
            teBoms.addAll(reset(teBom));
        }
        return teBoms;
    }

    private void createWord(EBOMWordInfo ebomWordInfo, String templateName, String filePath) {
        try {
            //创建配置实例
            Configuration configuration = new Configuration();
            //设置编码
            configuration.setDefaultEncoding("UTF-8");
            configuration.setDirectoryForTemplateLoading(new File(fileService.getRelativePath() + "/file"));
            //获取模板
            Template template = configuration.getTemplate(templateName);
            //输出文件
            File outFile = new File(filePath);
            //如果输出目标文件夹不存在，则创建
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            //将模板和数据模型合并生成文件
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
            //生成文件
            template.process(ebomWordInfo, out);
            //关闭流
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized String doExportAllEBomInfoToWord(String id) {
        TEBom teBom = findOne(id);
        List<TEBom> teBoms = reset(teBom);
        String path = "/temp/" + new Date().getTime() + "/" + teBom.getId();
        for (TEBom teBom1 : teBoms) {
            buildWordFile(teBom1.getId(), path);
        }
        OutputStream outputStream = null;
        String dirPath = fileService.getRelativePath() + path;
        File file = new File(dirPath);
        try {
            String strZipName = dirPath + ".zip";
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(strZipName));
            FileUtils.zip(file, out, false);
            out.close();
            FileUtils.deleteDirectory(file);
        } catch (Exception ex) {

        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return path + ".zip";
    }

    private synchronized String buildWordFile(String id, String path) {
        TEBom teBom = findOne(id);
//        开始封装EBOM
        EBOMWordInfo ebomWordInfo = new EBOMWordInfo();
        ebomWordInfo.setCurrent(teBom);
        teBom.setNodeLevel(1);
        ebomWordInfo.setTreeData(reset(teBom));
        teBom.gettPBom().setNodeLevel(1);
        ebomWordInfo.setpBomTreeData(sysPBomService.reset(teBom.gettPBom()));
        ebomWordInfo.setTops(findTop(teBom));
        ebomWordInfo.setTopPboms(sysPBomService.findTop(teBom.gettPBom()));

        List<TProcessRecord> records = teBom.gettProcessRecords();
        Collections.sort(records, new Comparator<TProcessRecord>() {

            public int compare(TProcessRecord processRecord, TProcessRecord processRecord2) {
                return processRecord.getOperateTime().compareTo(processRecord2.getOperateTime());
            }
        });
        List<EBOMWordInfo.LabData> labDatas = new ArrayList<EBOMWordInfo.LabData>(records.size());
        Map<String, String> docPaths = new HashMap<String, String>();
        if (path == null) {
            path = "/temp/" + new Date().getTime() + "/" + teBom.getId();
        }
        String dirPath = fileService.getRelativePath() + path;
        //转换word文件
        File file = new File(dirPath);
        file.mkdirs();

        for (TProcessRecord record : records) {
            EBOMWordInfo.LabData labData = new EBOMWordInfo.LabData();
            labData.setOperator(record.getOperator());
            labData.setResult(record.getResult());
            labData.setTitle(record.gettProcessTemplate().getProcessName());
            labData.setOperateTime(DateFormatUtils.format(record.getOperateTime(), "yyyy年MM月dd日 HH时mm分ss秒"));

            //系统录入数据
            List<EBOMWordInfo.Param> params = new ArrayList<EBOMWordInfo.Param>();
            for (TProcessParameter processParameter : record.gettProcessParameters()) {
                EBOMWordInfo.Param param = new EBOMWordInfo.Param(
                        processParameter.getFieldName(),
                        processParameter.getParameterValue(),
                        processParameter.getParameterDevice(),
                        processParameter.getUnit()
                );
                param.convert(processParameter.getFieldType(), fileService.getRelativePath(), dirPath);
                params.add(param);
            }
            labData.setParams(params);
            TExperimentalData experimentalData = record.gettExperimentalData();
//            实验数据
            if (experimentalData != null && (BaseConstant.DataParseStatus.SUCCESS_LOAD_DATA.name().equals(experimentalData.getStatus())
                    || BaseConstant.DataParseStatus.SUCCESS_DRAW.name().endsWith(experimentalData.getStatus()))) {
                EBOMWordInfo.GrantData grantData = new EBOMWordInfo.GrantData();
                String uuid = UUID.randomUUID().toString();
                docPaths.put(experimentalData.getExperimentalDataPath() + "/data.xls", uuid + ".xls");
                grantData.setExcelPath(uuid + ".xls");

                List<EBOMWordInfo.GrantParam> paramList = new ArrayList<EBOMWordInfo.GrantParam>();

                String jsonFile = experimentalData.getExperimentalDataPath() + "/data.json";
                try {
                    String json = FileUtils.readFileToString(new File(fileService.getRelativePath() + jsonFile), "UTF-8");
                    JSONObject jsonObject = JSON.parseObject(json);
                    JSONArray labels = jsonObject.getJSONArray("labels");
                    if (labels != null && labels.size() > 0) {
                        for (int i = 0; i < labels.size(); i++) {
                            JSONObject jb = labels.getJSONObject(i);
                            paramList.add(new EBOMWordInfo.GrantParam("实验数据", jb.getString("text"), jb.getString("type")));
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (BaseConstant.INTEGER_TRUE.equals(experimentalData.getHasChart()) &&
                        BaseConstant.DataParseStatus.SUCCESS_DRAW.name().endsWith(experimentalData.getStatus())) {
                    String pngPath = experimentalData.getExperimentalDataPath() + "/data.png";
                    paramList.add(new EBOMWordInfo.GrantParam("指数图", pngPath, BaseConstant.LabelType.LABEL_TYPE_IMG.name()));
                }
                grantData.setGrantParams(paramList);
                //获取名称
                String code = experimentalData.getExperimentalDataPath()
                        .substring(experimentalData.getExperimentalDataPath().lastIndexOf("/") + 1);
                LabDataParser labDataParser = LabDataParser.valueOf(code);
                grantData.setTitle(labDataParser.getTitle());
                labData.setGrantData(grantData);
            }
            labDatas.add(labData);
        }
        ebomWordInfo.setLabDatas(labDatas);
        ebomWordInfo.buildMap(fileService.getRelativePath());

        createWord(ebomWordInfo, "wordInfo.ftl", dirPath + "/" + teBom.geteName() + ".doc");
        for (Map.Entry<String, String> doc : docPaths.entrySet()) {
            FileUtils.copy(new File(fileService.getRelativePath() + "/" + doc.getKey()),
                    new File(dirPath + "/" + doc.getValue()), true);
        }
        return path;
    }

    /**
     * 导出工件的所有信息
     * <p/>
     * 信息列表包括：1、清单文件 1、工件的PBom结构 2、工件的Ebom结构 3、工件每一次录入的参数， 工件的实验数据
     *
     * @param id
     * @return
     */
    public synchronized String doExportEBomInfoToWord(String id) {
        String path = buildWordFile(id, null);
        OutputStream outputStream = null;
        String dirPath = fileService.getRelativePath() + path;
        File file = new File(dirPath);
        try {
            String strZipName = dirPath + ".zip";
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(strZipName));
            FileUtils.zip(file, out, false);
            out.close();
            FileUtils.deleteDirectory(file);
        } catch (Exception ex) {

        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return path + ".zip";
    }

    public List<TEBom> findTop(final TEBom teBom) {
        //根据某一个叶子节点获取顶层节点
        List<TEBom> top = new ArrayList<TEBom>();
        Specification<TEBomRelation> teBomRelationSpecification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TEBomRelation>() {

            public void fillParam(Root<TEBomRelation> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("child").get("id"), teBom.getId()));
            }
        });
        List<TEBomRelation> teBoms = teBomRelationDAO.findAll(teBomRelationSpecification);
        if (teBoms.isEmpty()) {
            top.add(teBom);
        } else {
            for (TEBomRelation teBomRelation : teBoms) {
                top.addAll(findTop(teBomRelation.getRef()));
            }
        }
        return top;
    }

    private RowTemplate<TEBom> buildRowTemplate() {
        RowTemplate<TEBom> rowTemplate = new RowTemplate<TEBom>();
        rowTemplate.addColumnTemplate(new RowTemplate.ColumnTemplate<TEBom>("装配结构编码", new ColumnParser<TEBom>() {

            public WritableCell parse(int row, int cellNum, TEBom teBom) {
                return new Label(cellNum, row, teBom.getCode());
            }
        })).addColumnTemplate(new RowTemplate.ColumnTemplate<TEBom>("名称", new ColumnParser<TEBom>() {

            public WritableCell parse(int row, int cellNum, TEBom teBom) {
                return new Label(cellNum, row, teBom.geteName());
            }
        })).addColumnTemplate(new RowTemplate.ColumnTemplate<TEBom>("层次", new ColumnParser<TEBom>() {

            public WritableCell parse(int row, int cellNum, TEBom teBom) {
                return new Number(cellNum, row, teBom.getNodeLevel());
            }
        })).addColumnTemplate(new RowTemplate.ColumnTemplate<TEBom>("功能", new ColumnParser<TEBom>() {

            public WritableCell parse(int row, int cellNum, TEBom teBom) {
                return new Label(cellNum, row, teBom.getDescription());
            }
        })).addColumnTemplate(new RowTemplate.ColumnTemplate<TEBom>("备注", new ColumnParser<TEBom>() {
            public WritableCell parse(int row, int cellNum, TEBom teBom) {
                return new Label(cellNum, row, teBom.getRemark());
            }
        }));
        return rowTemplate;
    }

    /**
     * 导出EBOM结构
     *
     * @param id
     */
    public byte[] doExportEBomTop(String id) {
        final TEBom teBom = findOne(id);
        if (teBom == null) {
            throw new BusinessException("不存在的结构，导出失败");
        }
        teBom.setNodeLevel(1);
        List<TEBom> teBoms = reset(teBom);
        RowTemplate<TEBom> rowTemplate = buildRowTemplate();
        DataWriter<TEBom> tpBomDataWriter = new ExcelDataWriter<TEBom>(rowTemplate);
        try {
            return tpBomDataWriter.write(teBoms);
        } catch (Exception e) {
            throw new BusinessException("导出数据失败");
        }
    }

    /**
     * 导出EBOM结构
     *
     * @param id
     */
    public byte[] doExportEBom(String id) {
        final TEBom teBom = findOne(id);
        if (teBom == null) {
            throw new BusinessException("不存在的结构，导出失败");
        }
        teBom.setNodeLevel(1);
        List<TEBom> teBoms = reset(teBom);
        RowTemplate<TEBom> rowTemplate = buildRowTemplate();
        DataWriter<TEBom> tpBomDataWriter = new ExcelDataWriter<TEBom>(rowTemplate);
        try {
            return tpBomDataWriter.write(teBoms);
        } catch (Exception e) {
            throw new BusinessException("导出数据失败");
        }
    }

    /**
     * 添加EBOM
     *
     * @param teBom
     * @param number
     */
    public List<TEBom> addEBom(TEBom teBom, int number, List<EBomMake> eBomMakes) {
        if (number <= 0) {
            throw new BusinessException("至少需要装配一个工件");
        }
        TPBom tpBom = teBom.gettPBom();
        if (tpBom == null || StringUtils.isBlank(tpBom.getId())) {
            throw new BusinessException("未关联设计结构的装配结构不能生成");
        }
        tpBom = sysPBomService.findOne(tpBom.getId());
        if (tpBom == null) {
            throw new BusinessException("未关联设计结构的装配结构不能生成");
        }
        if (!BaseConstant.BomStatus.PUBLISH.name().equals(tpBom.getStatus())) {
            throw new BusinessException("未发布的设计结构不能关联装配结构");
        }
        teBom.setCreateTime(new Date());
        teBom.setCreateUser(AuthContextHelper.getLoginUser());
        teBom.setBomType(BaseConstant.EBomType.E_BOM_TYPE_UN_BUILD.name());
        teBom.setStatus(BaseConstant.BomStatus.PUBLISH.name());
        teBom.setUsed(BaseConstant.INTEGER_FALSE);
//        直接是根节点，不含有
        SearchEBomCondition searchEBomCondition = new SearchEBomCondition();
        searchEBomCondition.settPBom(tpBom);
        long ebomTotal = teBomDAO.count(buildSpecification(searchEBomCondition));
        List<TEBom> teBoms;
        if (ValidatorUtils.isArrayEmpty(tpBom.getTpBomRelations())) {
            //直接生成
            teBoms = new ArrayList<TEBom>();
            for (int i = 0; i < number; i++) {
                TEBom db = new TEBom();
                BeanUtils.copyProperties(teBom, db);
                ebomTotal++;
                db.setCode(tpBom.getCode() + "-" + ebomTotal);
                teBoms.add(db);
            }
            teBomDAO.save(teBoms);
        } else {
            //根据关系装配
            teBoms = doBuild(teBom, getChildren(tpBom), number, eBomMakes);
            List<TEBomRelation> teBomRelations = new ArrayList<TEBomRelation>();
            List<TEBom> children = new ArrayList<TEBom>();
            for (TEBom _ebom : teBoms) {
                ebomTotal++;
                _ebom.setCode(tpBom.getCode() + "-" + ebomTotal);
                teBomRelations.addAll(_ebom.gettEBomRelations());
                children.addAll(_ebom.getChildren());
                _ebom.settEBomRelations(null);
            }
            teBomDAO.save(teBoms);
            for (TEBom _bom : children) {
                _bom.setBomType(BaseConstant.EBomType.E_BOM_TYPE_BUILD.name());
            }
            teBomDAO.save(children);
            teBomRelationDAO.save(teBomRelations);
        }
        return teBoms;
    }

    /**
     * 回收组件
     *
     * @param id
     * @return
     */
    public TEBom recycle(final String id) {
        List<TEBomRelation> relations = teBomRelationDAO.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TEBomRelation>() {

            public void fillParam(Root<TEBomRelation> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("child").get("id").as(String.class), id));
            }
        }));
        for (TEBomRelation relation : relations) {
            relation.setStatus(BaseConstant.BomStatus.RECYCLE.name());
        }
        teBomRelationDAO.save(relations);
        TEBom teBom = findOne(id);
        teBom.setBomType(BaseConstant.EBomType.E_BOM_TYPE_UN_BUILD.name());
        teBom.setStatus(BaseConstant.BomStatus.RECYCLE.name());
        teBomDAO.save(teBom);
        return teBom;
    }


//    private void clearRelation(List<TEBom> refs) {
//        final List<String> codes = QueryHelper.doQueryProperties(refs, true, new QueryHelper.PropertyReader<TEBom, String>() {
//
//            public String read(TEBom teBom) {
//                return teBom.getCode();
//            }
//        });
//        Specification<TEBomRelation> relationSpecification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TEBomRelation>() {
//
//            public void fillParam(Root<TEBomRelation> root, CriteriaBuilder cb, List<Predicate> list) {
//                list.add(root.get("ref").get("code").as(String.class).in(codes));
//            }
//        });
//        List<TEBomRelation> relations = teBomRelationDAO.findAll(relationSpecification);
//        teBomRelationDAO.delete(relations);
//    }

    private List<TPBom> getChildren(TPBom tpBom) {
        List<TPBom> tpBoms = new ArrayList<TPBom>();
        List<TPBomRelation> tpBomRelations = tpBom.getTpBomRelations();
        for (TPBomRelation tpBomRelation : tpBomRelations) {
            TPBom child = tpBomRelation.getChild();
            child.setNumber(tpBomRelation.getNumber());
            tpBoms.add(child);
        }
        return tpBoms;
    }

    /**
     * 进行装配
     *
     * @param template
     * @param tpBoms
     * @param number
     * @param eBomMakes
     * @return
     */
    private List<TEBom> doBuild(TEBom template, List<TPBom> tpBoms, int number, List<EBomMake> eBomMakes) {
        Map<TPBom, List<TEBom>> tpBomListMap = new HashMap<TPBom, List<TEBom>>();
        for (TPBom tpBom : tpBoms) {
            tpBomListMap.put(tpBom, suitEBomMake(tpBom, number, eBomMakes));
        }
        List<TEBom> teBoms = new ArrayList<TEBom>(number);
        for (int i = 0; i < number; i++) {
            TEBom db = new TEBom();
            BeanUtils.copyProperties(template, db);
            db.settEBomRelations(new ArrayList<TEBomRelation>());
            for (Map.Entry<TPBom, List<TEBom>> entry : tpBomListMap.entrySet()) {
                TPBom tpBom = entry.getKey();
                List<TEBom> list = entry.getValue();
                List<TEBom> children = list.subList(i * tpBom.getNumber(), (i + 1) * tpBom.getNumber());
                for (TEBom child : children) {
                    db.addChild(child);
                }
            }
            teBoms.add(db);
        }
        return teBoms;
    }

    /**
     * 返回适合的工件
     *
     * @param tpBom
     * @param number
     * @param eBomMakes
     * @return
     */
    private List<TEBom> suitEBomMake(TPBom tpBom, int number, List<EBomMake> eBomMakes) {
        EBomMake _db = new EBomMake(tpBom);
        for (EBomMake eBomMake : eBomMakes) {
            if (eBomMake.getTpBom() != null && tpBom.getId().equals(eBomMake.getTpBom().getId())) {
                _db = eBomMake;
                break;
            }
        }
        if (_db.getSearchEBomCondition() == null) {
            _db.setSearchEBomCondition(new SearchEBomCondition());
        }
        int totalNum = number * tpBom.getNumber();
        List<TEBom> e = findPBomSpecificationEBoms(_db);
        if (e.size() < totalNum) {
            throw new BusinessException("现有的下级工件数不能达到当前所需工件数要求，装配失败！");
        }
        return e.subList(0, totalNum);
    }

    /**
     * 查询匹配的EBOM结构
     *
     * @return
     */
    private List<TEBom> findPBomSpecificationEBoms(EBomMake eBomMake) {
        SearchEBomCondition searchEBomCondition = eBomMake.getSearchEBomCondition();
        searchEBomCondition.settPBom(eBomMake.getTpBom());
        return teBomDAO.findAll(buildSpecification(searchEBomCondition));
    }

    /**
     * 查询eboms
     *
     * @param searchEBomCondition
     * @param pageable
     * @return
     */
    public Page<TEBom> findEBoms(SearchEBomCondition searchEBomCondition, Pageable pageable) {
        return teBomDAO.findAll(buildSpecification(searchEBomCondition), pageable);
    }

    /**
     * 查询eboms
     *
     * @param id
     * @return
     */

    public TEBom findOne(String id) {
        return StringUtils.isBlank(id) ? null : teBomDAO.findOne(id);
    }

    /**
     * 查询孩子节点
     *
     * @param id
     * @return
     */
    public List<TEBom> findChildren(String id) {
        TEBom parent = findOne(id);
        List<TEBom> children = parent.getChildren();
        if (children.size() > 3) {
            //根据PBOM分组
            Map<String, List<TEBom>> stringTEBomMap = new TreeMap<String, List<TEBom>>();
            for (TEBom teBom : children) {
                if (stringTEBomMap.get(teBom.gettPBom().getId()) == null) {
                    stringTEBomMap.put(teBom.gettPBom().getId(), new ArrayList<TEBom>());
                }
                stringTEBomMap.get(teBom.gettPBom().getId()).add(teBom);
            }
            children = new ArrayList<TEBom>();
            for (Map.Entry<String, List<TEBom>> tpBomEntry : stringTEBomMap.entrySet()) {
                List<TEBom> boms = tpBomEntry.getValue();
                //对于超过3条的下级结构不完全展示，只展示组信息，需点击详情进行查看，以减轻服务器压力
                if (boms.size() > 3) {
                    TEBom teBomGroup = new TEBom();
                    BeanUtils.copyProperties(boms.get(0), teBomGroup);
                    teBomGroup.setBomGroup(true);
                    teBomGroup.seteName(teBomGroup.geteName() + "...共计" + tpBomEntry.getValue().size() + "条资源");
                    children.add(teBomGroup);
                } else {
                    children.addAll(tpBomEntry.getValue());
                }
            }
        }
        return children;
    }

    private Specification<TEBom> buildSpecification(final SearchEBomCondition searchEBomCondition) {
        Specification<TEBom> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TEBom>() {

            public void fillParam(Root<TEBom> root, CriteriaBuilder cb, List<Predicate> list) {
                boolean searchAble = false;
                if (StringUtils.isNotBlank(searchEBomCondition.geteName())) {
                    searchAble = true;
                    list.add(cb.like(root.get("eName").as(String.class), "%" + searchEBomCondition.geteName() + "%"));
                }
                if (ValidatorUtils.isArrayNotEmpty(searchEBomCondition.getIds())) {
                    searchAble = true;
                    list.add(root.get("id").as(String.class).in(searchEBomCondition.getIds()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getId())) {
                    searchAble = true;
                    list.add(cb.equal(root.get("id").as(String.class), searchEBomCondition.getId()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getCode())) {
                    searchAble = true;
                    list.add(cb.equal(root.get("code").as(String.class), searchEBomCondition.getCode()));
                }
                if (searchEBomCondition.getBeginQuery() != null) {
                    searchAble = true;
                    list.add(cb.greaterThanOrEqualTo(root.get("createTime").as(Date.class), searchEBomCondition.getBeginQuery()));
                }
                if (searchEBomCondition.getEndQuery() != null) {
                    searchAble = true;
                    list.add(cb.lessThanOrEqualTo(root.get("createTime").as(Date.class), searchEBomCondition.getEndQuery()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getBomType())) {
                    searchAble = true;
                    list.add(cb.equal(root.get("bomType").as(String.class), searchEBomCondition.getBomType()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getStatus())) {
                    searchAble = true;
                    list.add(cb.equal(root.get("status").as(String.class), searchEBomCondition.getStatus()));
                }
                if (searchEBomCondition.gettPBom() != null && StringUtils.isNotBlank(searchEBomCondition.gettPBom().getId())) {
                    searchAble = true;
                    list.add(cb.equal(root.get("tPBom").get("id").as(String.class), searchEBomCondition.gettPBom().getId()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getProcessId())) {
                    searchAble = true;
                    ListJoin<TEBom, TProcessRecord> listJoin = root.join(root.getModel().getList("tProcessRecords", TProcessRecord.class), JoinType.LEFT);
                    list.add(cb.equal(listJoin.get("tProcessTemplate").get("id").as(String.class), searchEBomCondition.getProcessId()));
                }
                if (StringUtils.isNotBlank(searchEBomCondition.getParentId())) {
                    searchAble = true;
                    CriteriaQuery query = cb.createQuery();
                    Subquery<TEBom> sq = query.subquery(TEBom.class);
                    Root<TEBomRelation> spouseEmp = sq.from(TEBomRelation.class);
                    sq.select(spouseEmp.get("child").as(TEBom.class));
                    sq.where(cb.equal(spouseEmp.get("ref").get("id").as(String.class), searchEBomCondition.getParentId()));
                    list.add(root.in(sq));
                }
                //过滤掉为做过实验的
                if (searchEBomCondition.getUsed() != null) {
                    searchAble = true;
                    list.add(cb.equal(root.get("used").as(Integer.class), searchEBomCondition.getUsed()));
                }
                if (ValidatorUtils.isArrayNotEmpty(searchEBomCondition.getConditions())) {
                    searchAble = true;
                    List<TProcessRecord> records = sysRecordMatchService.findByLabConditions(searchEBomCondition.getConditions());
                    if (records.isEmpty()) {
                        list.add(cb.equal(root.get("id").as(String.class), ""));
                    } else {
                        Set<String> ebomIds = new HashSet<String>();
                        for(TProcessRecord processRecord : records){
                            if(ValidatorUtils.isArrayNotEmpty(processRecord.getTeBoms())){
                                for(TEBom teBom : processRecord.getTeBoms()){
                                    ebomIds.add(teBom.getId());
                                }
                            }
                        }
                        list.add(cb.equal(root.get("used").as(Integer.class), BaseConstant.INTEGER_TRUE));
                        list.add(root.get("id").as(String.class).in(ebomIds));
                    }
                }
                if (searchEBomCondition.isRoot() && !searchAble) {
                    CriteriaQuery query = cb.createQuery();
                    Subquery<TEBom> sq = query.subquery(TEBom.class);
                    Root<TEBomRelation> spouseEmp = sq.from(TEBomRelation.class);
                    sq.select(spouseEmp.get("child").as(TEBom.class));
                    list.add(root.in(sq).not());
                }
            }
        });
        return specification;
    }
}
